package cn.etynit.service.impl;

import cn.etynit.domain.*;
import cn.etynit.dto.*;
import cn.etynit.exception.GlobalException;
import cn.etynit.exception.GlobalExceptionCodeEnum;
import cn.etynit.mapper.EmployeeMapper;
import cn.etynit.mms.feign.*;
import cn.etynit.result.JsonResult;
import cn.etynit.service.IEmployeeService;
import cn.etynit.util.AssertUtil;
import cn.etynit.util.BaiduAuditUtils;
import cn.etynit.vo.Logininfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.sound.midi.Soundbank;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author etyn
 * @since 2022-12-09
 */
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {

    @Autowired
    private UserService userService;

    @Autowired
    private ExpenseElectricityService expenseElectricityService;

    @Autowired
    private ExpenseTapWaterService expenseTapWaterService;

    @Autowired
    private ExpenseNaturalGasService expenseNaturalGasService;

    @Autowired
    private ExpenseService expenseService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private ExpenseCarService expenseCarService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private InformService informService;

    public static final String INITIALIZE_PARKING_METER_SUCCEED = "添加停车位成功！";


    /**
     * 账单生成
     * @param billDto
     * @return
     */
    @Override
    public JsonResult billGeneration(BillDto billDto,String token) {
        // 参数校验
        Logininfo logininfo = (Logininfo)redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // redis里面的登录信息为空表示登录过期
        AssertUtil.isTrue(logininfo.getType() == 1,GlobalExceptionCodeEnum.ERROR); // 登录人员必须是平台管理员，否则没有权限操作
        // 查询校验业主
        Long userId = billDto.getUserId();
        JsonResult result = userService.get(userId);
        AssertUtil.isTrue(result.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 调用user服务查询，查询失败报错
        Object obj = result.getData();
        AssertUtil.isNotNull(obj,GlobalExceptionCodeEnum.ERROR); // 查询的业主不能为空
        User user = JSON.parseObject(JSONObject.toJSONString(obj), User.class);
        AssertUtil.isNotNull(user,GlobalExceptionCodeEnum.ERROR); // 查询的业主不能为空
        // 参数校验-金额
        BigDecimal money = billDto.getMoney();
        int i = money.compareTo(BigDecimal.ZERO);
        if (i < 0){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // BigDecimal大小比较，账单金额不能比0小
        }
        // 参数校验-月份
        Integer month = billDto.getMonth();
        if (!(1 <= month && month <= 12)){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 月份校验，必须在1-12月份之间
        }
        // 参数校验-缴费类型
        Integer costType = billDto.getType();
        // 添加费用明细表
        Expense expense = new Expense();
        expense.setUserId(userId);
        expense.setEmployeeId(logininfo.getId().longValue());
        expense.setMonth(month);
        expense.setMoney(money);
        expense.setTime(new Date());
        expense.setPay(Expense.NON_PAYMENT);
        expense.setType(costType);
        // 添加相应账单表
        if (costType == 1){ // 电费
            JsonResult jsonResult = expenseElectricityService.selectByUserId(userId);
            AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR); //查询用户电费表失败报错
            Object data = jsonResult.getData();
            AssertUtil.isNotNull(data,GlobalExceptionCodeEnum.ERROR); // 电费表不能为空
            ExpenseElectricity expenseElectricity = JSON.parseObject(JSONObject.toJSONString(data), ExpenseElectricity.class);
            AssertUtil.isNotNull(expenseElectricity,GlobalExceptionCodeEnum.ERROR); // 电费表不能为空
            expenseElectricity.setAccumulative(money);
            expenseService.saveOrUpdate(expense);
            return expenseElectricityService.saveOrUpdate(expenseElectricity);
        } else if (costType == 2){ // 水费
            JsonResult jsonResult = expenseTapWaterService.selectByUserId(userId);
            AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR); //查询用户水费表失败报错
            Object data = jsonResult.getData();
            AssertUtil.isNotNull(data,GlobalExceptionCodeEnum.ERROR); // 水费表不能为空
            ExpenseTapWater expenseTapWater = JSON.parseObject(JSONObject.toJSONString(data), ExpenseTapWater.class);
            AssertUtil.isNotNull(expenseTapWater,GlobalExceptionCodeEnum.ERROR); // 水费表不能为空
            expenseTapWater.setAccumulative(money);
            expenseService.saveOrUpdate(expense);
            return expenseTapWaterService.saveOrUpdate(expenseTapWater);
        } else if (costType == 3){ // 燃气费
            JsonResult jsonResult = expenseNaturalGasService.selectByUserId(userId);
            AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR); //查询用户燃气费表失败报错
            Object data = jsonResult.getData();
            AssertUtil.isNotNull(data,GlobalExceptionCodeEnum.ERROR); // 燃气费表不能为空
            ExpenseNaturalGas expenseNaturalGas = JSON.parseObject(JSONObject.toJSONString(data), ExpenseNaturalGas.class);
            AssertUtil.isNotNull(expenseNaturalGas,GlobalExceptionCodeEnum.ERROR); // 燃气费表不能为空
            expenseNaturalGas.setAccumulative(money);
            expenseService.saveOrUpdate(expense);
            return expenseNaturalGasService.saveOrUpdate(expenseNaturalGas);
        } else {
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 费用类型不对则报错
        }
    }

    /**
     * 发布社区活动
     * @param activityDto
     * @return
     */
    @Override
    public JsonResult releaseActivity(ActivityDto activityDto,String token) {
        // 通过前端传递的token获取redis中的logininfo
        Logininfo logininfo = (Logininfo)redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 如果为空证明登录已过期
        Integer type = logininfo.getType();
        AssertUtil.isTrue(type == 1,GlobalExceptionCodeEnum.ERROR); // 获取登录类型，为1才是员工登录的信息,否则报错
        String phone = logininfo.getPhone(); // 获取当前员工phone
        Wrapper<Employee> wrapper = new EntityWrapper<>();
        wrapper.eq("phone",phone);
        Employee employee = selectOne(wrapper);
        AssertUtil.isTrue(employee.getType() == 1,GlobalExceptionCodeEnum.ERROR); // 员工类型为1才是管理，有权操作，不然报错
        Long employeeId = employee.getId();
        Date expirationTime = activityDto.getExpirationTime(); // 获取活动过期时间
        // 活动标题校验
        String title = activityDto.getTitle();
        Boolean booTitle = BaiduAuditUtils.TextCensor(title);
        AssertUtil.isTrue(booTitle,GlobalExceptionCodeEnum.ERROR); // 活动标题审核不通过则报错
        // 通过活动标题校验活动是否已存在
        activityService.findByTitle(title);
        // 活动内容校验
        String details = activityDto.getDetails();
        Boolean booDetails = BaiduAuditUtils.TextCensor(details);
        AssertUtil.isTrue(booDetails,GlobalExceptionCodeEnum.ERROR); // 活动内容审核不通过则报错
        // 活动图片校验
        String img = activityDto.getImg();
//        if (img != null){
//            Boolean booImg = BaiduAuditUtils.ImgCensor(img);
//            AssertUtil.isTrue(booImg,GlobalExceptionCodeEnum.ERROR);
//            activityDto.setImg(img);
//        }
        // 初始化活动表
        Activity activity = new Activity();
        if (img != null){
            activity.setImg(img);
        }
        activity.setEmployeeId(employeeId);
        activity.setTime(new Date());
        activity.setExpirationTime(expirationTime);
        activity.setTitle(title);
        activity.setDetails(details);
        return activityService.saveOrUpdate(activity);
    }

    /**
     * 业主办理停车位
     * @param parkingSpaceDto
     * @return
     */
    @Override
    public JsonResult registerForParking(ParkingSpaceDto parkingSpaceDto,String token) {
        // 校验登录及员工是不是管理员
        Logininfo logininfo = (Logininfo) redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 如果为空证明登录已过期
        Integer type = logininfo.getType();
        AssertUtil.isTrue(type == 1,GlobalExceptionCodeEnum.ERROR); // 获取登录类型，为1才是员工登录的信息,否则报错
        Long employeeId = logininfo.getId();
        // 查询员工是否存在
        Long userId = parkingSpaceDto.getUserId();
        JsonResult jsonResult = userService.get(userId);
        AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 查询业主失败报错
        User user = JSON.parseObject(JSONObject.toJSONString(jsonResult.getData()), User.class);
        AssertUtil.isNotNull(user.getId(),GlobalExceptionCodeEnum.ERROR); // 业主不存在报错
        JsonResult selectExpenseCar = expenseCarService.selectByUserId(userId);
        AssertUtil.isTrue(selectExpenseCar.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 停车位业主只能办理一次，以办理过了报错
        // 车牌号校验
        String number = parkingSpaceDto.getNumber();
        AssertUtil.isLicencePlate(number,GlobalExceptionCodeEnum.ERROR); // 车牌号不对报错
        // 剩余小汽车位校验
        JsonResult result = expenseCarService.surplusParkingSpace(ExpenseCar.DONKEY_ENGINE);
        AssertUtil.isTrue(result.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 车位不够报错
        Integer carType = parkingSpaceDto.getCarType();
        ExpenseCar expenseCar = new ExpenseCar();
        Expense expense = new Expense();
        BigDecimal bigDecimal = new BigDecimal(0);
        if (carType == 0 || carType == 1){
            // 添加停车费表
            expenseCar.setNumber(number);
            expenseCar.setUserId(userId);
            expenseCar.setAccumulative(bigDecimal);
            expenseCar.setResidue(bigDecimal);
            expenseCar.setType(carType);
            expenseCar.setEmployeeId(employeeId);
            JsonResult jsonResultExpenseCar = expenseCarService.saveOrUpdate(expenseCar);
            AssertUtil.isTrue(jsonResultExpenseCar.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 停车费用表添加失败报错
            // 添加费用表
            expense.setUserId(userId);
            expense.setEmployeeId(employeeId);
            expense.setType(Expense.PARKING_CHARGE);
            JsonResult jsonResultExpense = expenseService.saveOrUpdate(expense);
            AssertUtil.isTrue(jsonResultExpense.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 费用表添加失败报错
            return JsonResult.success(INITIALIZE_PARKING_METER_SUCCEED);
        } else {
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 停车类型不对报错
        }
    }

    /**
     * 员工登录
     * @param accountLoginDto
     * @return
     */
    @Override
    public Employee accountLogin(AccountLoginDto accountLoginDto) {
        String account = accountLoginDto.getAccount();
        String password = accountLoginDto.getPassword();
        Wrapper<Employee> wrapper = new EntityWrapper<>();
        wrapper.eq("account",account);
//        wrapper.eq("password",password);
        Employee employee = selectOne(wrapper);
        if (employee == null){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 账号错误
        }
        String pws = employee.getPassword();
        if (!password.equals(pws)){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 密码错误
        }
        return employee;
    }

    /**
     * 通知发布
     * @param informPublishDto
     * @param token
     * @return
     */
    @Override
    public JsonResult informPublish(InformPublishDto informPublishDto, String token) {
        // redis获取登录信息
        Logininfo logininfo = (Logininfo) redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 为空表明登录过期
        // 初始化Inform通知对象
        Long employeeId = logininfo.getId();
        Inform inform = new Inform();
        inform.setTime(new Date());
        inform.setExpirationTime(informPublishDto.getExpirationTime());
        inform.setEmployeeId(employeeId);
        inform.setDetails(informPublishDto.getDetails());
        String img = informPublishDto.getImg();
        if (img != null){
            inform.setImg(img);
        }
        inform.setTitle(informPublishDto.getTitle());
        return informService.saveOrUpdate(inform);
    }
}
